package com.danieltoms.gcSync.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import net.rim.device.api.crypto.BlockDecryptor;
import net.rim.device.api.crypto.BlockEncryptor;
import net.rim.device.api.crypto.CryptoTokenException;
import net.rim.device.api.crypto.CryptoUnsupportedOperationException;
import net.rim.device.api.crypto.PKCS5FormatterEngine;
import net.rim.device.api.crypto.PKCS5UnformatterEngine;
import net.rim.device.api.crypto.TripleDESDecryptorEngine;
import net.rim.device.api.crypto.TripleDESEncryptorEngine;
import net.rim.device.api.crypto.TripleDESKey;
import net.rim.device.api.util.DataBuffer;

public class CryptoUtil
{
	CryptoUtil()
	{
	}

	private static final byte[] cryptoKey = "sdfalkjflkjflkjlfdjalfjdlajflksfjlsakfjlsjdljl".getBytes();

	public static String encryptString(String value)
	{
		try
		{
			// We are going to use TripleDES as the algorithm for
			// encrypting and decrypting the data. It is a very
			// common algorithm and was chosen because of this fact.

			// Create the new TripleDESKey. This creates a new random
			// TripleDESKey.
			TripleDESKey key = new TripleDESKey(cryptoKey);

			// Create the encryption engine for encrypting the data.
			TripleDESEncryptorEngine encryptionEngine = new TripleDESEncryptorEngine(key);

			// Due to the fact that in most cases the data that you are going to
			// encrypt will not fit perfectly into the block length of a cipher
			// we want to use a padding algorithm to pad out the last block if
			// necessary for us. We are going to use PKCS5 to do the padding for
			// us.
			PKCS5FormatterEngine formatterEngine = new PKCS5FormatterEngine(encryptionEngine);

			// Use the byte array output stream to catch the encrypted
			// information.
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

			// Create a block encryptor which will help us use the triple des
			// engine.
			BlockEncryptor encryptor = new BlockEncryptor(formatterEngine, outputStream);

			// Encrypt the actual data.
			encryptor.write(value.getBytes());

			// Close the stream.
			// This forces the extra bytes to be padded out if there was not
			// enough bytes
			// to fill all of the blocks.
			encryptor.close();

			// Get the actual encrypted data.
			return outputStream.toString();

		}
		catch (CryptoTokenException e)
		{
			System.out.println(e.toString());
		}
		catch (CryptoUnsupportedOperationException e)
		{
			System.out.println(e.toString());
		}
		catch (IOException e)
		{
			System.out.println(e.toString());
		}

		return "fail";
	}

	public static String decryptString(String value)
	{

		try
		{
			// End of Encryption
			// -----------------------------------------------------------------------------------------------
			// Beginning of Decryption

			// Now we are going to do the opposite side. We want to decrypt the
			// data and ensure
			// that the message we get back is going to be the same.
			// Note that since this is a symmetric algorithm we want to use the
			// same key as before.
			TripleDESKey key = new TripleDESKey(cryptoKey);
			TripleDESDecryptorEngine decryptorEngine = new TripleDESDecryptorEngine(key);

			// Create the unformatter engine that will remove any of the padding
			// bytes.
			PKCS5UnformatterEngine unformatterEngine = new PKCS5UnformatterEngine(decryptorEngine);

			// Set up an input stream to hand the encrypted data into the block
			// decryptor.
			ByteArrayInputStream inputStream = new ByteArrayInputStream(value.getBytes());

			// Create the block decryptor passing in the unformatter engine and
			// the encrypted data.
			BlockDecryptor decryptor = new BlockDecryptor(unformatterEngine, inputStream);

			// Now we want to read from the stream.
			// We are going to read the data in 10 bytes at a time and then add
			// that
			// new data onto the decryptedData array. It is important to note
			// that for efficiency one would most likely want to use a larger
			// value
			// than 10. We used a small value so that we could demonstrate
			// several
			// iterations through the loop.
			byte[] temp = new byte[10];
			DataBuffer db = new DataBuffer();
			for (;;)
			{
				int bytesRead = decryptor.read(temp);
				if (bytesRead <= 0)
				{
					// We have run out of information to read.
					// Bail.
					break;
				}
				db.write(temp, 0, bytesRead);
			}

			// Now we want to ensure that the decrypted data is the same as the
			// data we passed into the encryptor.
			byte[] decryptedData = db.toArray();

			return new String(decryptedData);

		}
		catch (CryptoTokenException e)
		{
			System.out.println(e.toString());
		}
		catch (CryptoUnsupportedOperationException e)
		{
			System.out.println(e.toString());
		}
		catch (IOException e)
		{
			System.out.println(e.toString());
		}

		return "fail";
	}

}
